package upm.pb4agent.team3;

import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.Codec;
import jade.content.lang.Codec.CodecException;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.OntologyException;
import jade.content.onto.UngroundedException;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.SimpleBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import java.util.ArrayList;
import java.util.List;

import upm.pb4agent.ontology.AssignBoat;
import upm.pb4agent.ontology.DenyRow;
import upm.pb4agent.ontology.PB4AgentOntology;
import upm.pb4agent.ontology.PickSeat;
import upm.pb4agent.ontology.RealRow;
import upm.pb4agent.ontology.Row;
import upm.pb4agent.ontology.Seat;

/**
 * This agent has the following functionality: 
 * <ul>
 * <li> TeamManager decides where is the dock where Rower board the boat.
 * <li> Waits for being allowed to board the boat on designed Dock
 * <li> 
 *      
 * </ul>
 * @author Team 3, UPM
 * @version $Date: 2012/04/17 11:23:35 $ $Revision: 1.1 $
 **/

public class Rower extends Agent {
	private static final long serialVersionUID = -2396342030572691219L;
	private Codec codec = new SLCodec();
	private Ontology ontology = PB4AgentOntology.getInstance();
	
	private AID agWatcherAid = null;
		
	public upm.pb4agent.ontology.Boat boatTeam = null;
	private AID agBoatAid = null;
	public String currentDock ="";
	
	private String dock;
	private boolean yaEstoyRemando = false;
	//private Row rowCurrent = null;
	//private String seat = null;
	//private String oar;
	
	public double timeRow = 0.5;
	public double rowSeconds = 0.5;	
	public double tiredness = 0.5;
	
	public double impulseWeak = 0.5;
	public double impulseMedium = 0.5;
	public double impulseStrong = 0.5;
	
	public double timeChangeSeat = 0.5;
	
	private int rowerNumber = 1;
	public double strength = 0.5;
	public double resistance = 0.5;
	public double agility = 0.5;
	
	public boolean isRaceFinished = false;
	
	public Estrategia estrategia;
	
			
	public String getDock() {
		return dock;
	}
	
	protected void setup(){
		try{
			getContentManager().registerLanguage(codec);
			getContentManager().registerOntology(ontology);
			
			System.out.println(getLocalName() + ": enters the system");
			Object[] args = getArguments();
			
			for(int i=0; i<args.length;i++) {
				this.dock = (String) args[0];
				this.rowerNumber = Integer.parseInt((String)args[1]);				
			}
			
			readPhysicalProperties();
			currentDock = Constant.NAME_DOCK_A;
			estrategia = new Estrategia();
		}catch(Exception e){
			System.out.println(Constant.NAME_ROWER  + "-::-"  + e.toString());
			 e.printStackTrace();
		}
		
		agWatcherAid = MyAgent.searchAgentInDF(this,Constant.SD_WATCHER_X + Constant.TEAM_ID);
		//print();
		addBehaviour(new ProcessingBoatAssignationFromWatcher(this));
		addBehaviour(new SubscriptionInitiatorRowerToReferee(this));
	}
	
	public String toString(){
		StringBuffer rowerStrBuff = new StringBuffer();		
		rowerStrBuff.append("<");
		rowerStrBuff.append(getLocalName());
		rowerStrBuff.append(" :impulse_weak: " + this.impulseWeak);
		rowerStrBuff.append(" :impulse_medium: " + this.impulseMedium);
		rowerStrBuff.append(" :impulse_strong: " + this.impulseStrong);
		rowerStrBuff.append(" :dock: " + this.dock);
		rowerStrBuff.append(" :resistance: " + this.resistance);
		rowerStrBuff.append(" :strength: " + this.strength);
		rowerStrBuff.append(" :agility: " + this.agility);
		rowerStrBuff.append(">");
		return rowerStrBuff.toString();
	}
	
	public void print(){
		System.out.println(this.toString());
	}
	
	protected void takeDown(){
		System.out.println(getLocalName() + ", was terminated.");
	}
	
	
	class ProcessingBoatAssignationFromWatcher extends SimpleBehaviour{

		private static final long serialVersionUID = 3844912585144138107L;

		private boolean isDone = false;

		public ProcessingBoatAssignationFromWatcher(Agent agent) {
			super(agent);
		}

		public void action() {
			ACLMessage message = receive(MessageTemplate.and(
															 MessageTemplate.and(
																	              MessageTemplate.and(
																										MessageTemplate.MatchLanguage(codec.getName()),
																										MessageTemplate.MatchOntology(ontology.getName())
																					                 )
																				 ,MessageTemplate.MatchPerformative(ACLMessage.INFORM)
																				 )
															,MessageTemplate.MatchProtocol("AssignBoat"))
															);
			
			if (message != null) {
				ContentElement contentElement;
				try {
					contentElement = getContentManager().extractContent(message);
					if (contentElement instanceof Action) {
						Action action = (Action) contentElement;
						Concept concept = action.getAction();

						if(concept instanceof AssignBoat) {
							AssignBoat assignedBoat = (AssignBoat) concept;					
							boatTeam = assignedBoat.getBoat();
							System.out.println(getLocalName() + " AssignBoat <-- '" + boatTeam.getID().getLocalName() + "' from: " + Constant.SD_WATCHER_X + Constant.TEAM_ID );
							
							super.myAgent.addBehaviour(new ProcessPhysicalInformationFromWatcher(this.myAgent));							
							
							isDone = true;
						}
					}
				}catch (UngroundedException e) {
					e.printStackTrace();
				}catch (CodecException e) {
					e.printStackTrace();
				}catch (OntologyException e) {
					e.printStackTrace();
				}
			}else{
				block();
			}
		}

		public boolean done() {
			return isDone;
		}
	}
	boolean seatA=false;
	boolean seatB=false;
	boolean seatC=false;
	boolean seatD=false;
	
	public boolean pickingSeatToBoat(boolean isTaked, String nameDock) {
		try{			
			if(boatTeam == null) return false;
			
			/*System.out.println(getLocalName() + " SOY Estrategia A " + estrategia.estrategiaBeanDockA.getNameRower());
			System.out.println(getLocalName() + " SOY Estrategia B " + estrategia.estrategiaBeanDockB.getNameRower());
			System.out.println(getLocalName() + " SOY Estrategia C " + estrategia.estrategiaBeanDockC.getNameRower());
			System.out.println(getLocalName() + " SOY Estrategia D " + estrategia.estrategiaBeanDockD.getNameRower());*/
			
			if(getLocalName().equals(estrategia.estrategiaBeanDockA.getNameRower())){
				if(nameDock.equals(Constant.NAME_DOCK_A) && !seatA){
					seatA = true;
					Seat seat = new Seat();
					seat.setSeatID(estrategia.estrategiaBeanDockA.getNameSeat());					
					//
					PickSeat pickSeat = new PickSeat();
					pickSeat.setSeatID(seat);
					
					Action actionPickSeat = new Action(boatTeam.getID(), pickSeat);
					
					ACLMessage aclMessage = new ACLMessage(ACLMessage.INFORM);
			
					aclMessage.setLanguage(codec.getName());
					aclMessage.setOntology(ontology.getName());
					aclMessage.addReceiver(boatTeam.getID());
					aclMessage.setProtocol("PickSeat");
					
					getContentManager().fillContent(aclMessage, actionPickSeat);
					send(aclMessage);
					
				}
			}
			
			if(getLocalName().equals(estrategia.estrategiaBeanDockB.getNameRower())){
				if(nameDock.equals(Constant.NAME_DOCK_B) && !seatB){
					seatB = true;
					Seat seat = new Seat();
					seat.setSeatID(estrategia.estrategiaBeanDockB.getNameSeat());
					
					//
					PickSeat pickSeat = new PickSeat();
					pickSeat.setSeatID(seat);
					
					Action actionPickSeat = new Action(boatTeam.getID(), pickSeat);
					
					ACLMessage aclMessage = new ACLMessage(ACLMessage.INFORM);
			
					aclMessage.setLanguage(codec.getName());
					aclMessage.setOntology(ontology.getName());
					aclMessage.addReceiver(boatTeam.getID());
					aclMessage.setProtocol("PickSeat");
					
					getContentManager().fillContent(aclMessage, actionPickSeat);
					send(aclMessage);
					
				}
			}
			
			if(getLocalName().equals(estrategia.estrategiaBeanDockC.getNameRower())){
				if(nameDock.equals(Constant.NAME_DOCK_C)  && !seatC){
					seatC = true;
					Seat seat = new Seat();
					seat.setSeatID(estrategia.estrategiaBeanDockC.getNameSeat());
					
					//
					PickSeat pickSeat = new PickSeat();
					pickSeat.setSeatID(seat);
					
					Action actionPickSeat = new Action(boatTeam.getID(), pickSeat);
					
					ACLMessage aclMessage = new ACLMessage(ACLMessage.INFORM);
			
					aclMessage.setLanguage(codec.getName());
					aclMessage.setOntology(ontology.getName());
					aclMessage.addReceiver(boatTeam.getID());
					aclMessage.setProtocol("PickSeat");
					
					getContentManager().fillContent(aclMessage, actionPickSeat);
					send(aclMessage);
				}
			}
			
		   if(getLocalName().equals(estrategia.estrategiaBeanDockD.getNameRower())){
				if(nameDock.equals(Constant.NAME_DOCK_D)  && !seatD){
					seatD = true;
					Seat seat = new Seat();
					seat.setSeatID(estrategia.estrategiaBeanDockD.getNameSeat());
					
					//
					PickSeat pickSeat = new PickSeat();
					pickSeat.setSeatID(seat);
					
					Action actionPickSeat = new Action(boatTeam.getID(), pickSeat);
					
					ACLMessage aclMessage = new ACLMessage(ACLMessage.INFORM);

					aclMessage.setLanguage(codec.getName());
					aclMessage.setOntology(ontology.getName());
					aclMessage.addReceiver(boatTeam.getID());
					aclMessage.setProtocol("PickSeat");
					
					getContentManager().fillContent(aclMessage, actionPickSeat);
					send(aclMessage);
				}
			}
								
			return false;
		}catch(Exception e) {
			System.out.println(getLocalName() + ".pickingSeatToBoat(), error: " + e.toString());
			e.printStackTrace();
			return false;
		}
	}
	
	
	public void addBehaviourProcessSeatResponseFromBoat(){
		this.addBehaviour(new ProcessSeatResponseFromBoat(this));
	}

	class ProcessPhysicalInformationFromWatcher extends SimpleBehaviour{
		private static final long serialVersionUID = 3844912585144138107L;
		private boolean isDone = false;		
		
		public ProcessPhysicalInformationFromWatcher(Agent agent) {
			super(agent);
		}

		public void action(){
			try{				
				List<Integer> performativeList = new ArrayList<Integer>(3);
				performativeList.add(ACLMessage.INFORM);
				performativeList.add(ACLMessage.REFUSE);
				performativeList.add(ACLMessage.NOT_UNDERSTOOD);
				List<String> protocolList = new ArrayList<String>(3);
				//protocolList.add("Row");
				protocolList.add("RealRow");
				protocolList.add("DenyRow");
				MessageTemplate mt = MyAgent.addMessageTemplatOR(performativeList, protocolList);				
				ACLMessage msg =  receive(mt);				
				if(msg == null){
					block();
				}else{					
					try{
						ContentElement contentElement = getContentManager().extractContent(msg);
						if(contentElement instanceof Action) {
							Action action = (Action) contentElement;
							Concept concept = action.getAction();						
							if(msg.getPerformative() == ACLMessage.INFORM){	
								if (concept instanceof RealRow) {
									RealRow realRow = (RealRow)concept;									 
									
									//System.out.println(getLocalName() + ": <-- RealRow to 'x=" + realRow.getX() + ", y=" + realRow.getY() + "' from: " + msg.getSender());																
								}else if (concept instanceof DenyRow) {
									DenyRow denyRow = (DenyRow)concept;
									//System.out.println(getLocalName() + ": <-- DenyRow oar: " + denyRow.getOarID() + " from: " + msg.getSender());									
								}
							}else if(msg.getPerformative() == ACLMessage.REFUSE){		
								System.out.println(getLocalName()+ " <-- el watcher REFUSE el Row");
							}else if(msg.getPerformative() == ACLMessage.NOT_UNDERSTOOD){
								System.out.println(getLocalName()+ " <-- el watcher NOT_UNDERSTOOD el Row");
							}
						}
						
					}catch(Exception e){
						System.out.println(getLocalName() + ".ProcessPhysicalInformationFromWatcher(), error: " + e.toString());
					}
					isDone = true;
				}
			}catch(Exception e) {
				System.out.println(Constant.NAME_ROWER + ".ProcessPhysicalInformationFromWatcher(), error: " + e.toString());
			}
		}

		public boolean done() {
			return isDone;
		}
	}
	
	
	private String getRowInfo(Row row) {
		StringBuffer strBff = new StringBuffer();
		strBff.append(": Rowing <Boat: " + row.getBoat().getID().getLocalName());
		strBff.append(", Oar: " + row.getOarID());
		strBff.append(", Direction: " + row.getDirection());
		strBff.append(", Strength: " + row.getStrength() + ">");
		
		return strBff.toString();
	}
		
	
	public void addBehaviourStartRowingToWatcherBehavoiur(){
		this.addBehaviour(new StartRowingToWatcherBehavoiur(this));
	}	
	public class StartRowingToWatcherBehavoiur extends SimpleBehaviour{
		private static final long serialVersionUID = 3844912585144138107L;				
		
		public StartRowingToWatcherBehavoiur(Agent agent) {
			super(agent);
			isRaceFinished = false;
		}

		public void action(){
			try{				
				if(agWatcherAid == null){
					agWatcherAid = MyAgent.searchAgentInDF(super.myAgent,Constant.SD_WATCHER_X + Constant.TEAM_ID);
				}
				if(boatTeam != null){
					//System.out.println("estrategia.estrategiaDockVector.size()::" + estrategia.estrategiaDockVector.size());
					for(int i=0; i<estrategia.estrategiaDockVector.size(); i++){
						
						//if(  currentDock.equals(((EstrategiaBean)estrategia.estrategiaDockVector.get(i)).nameDock)){
							String nameRower = ((EstrategiaBean)estrategia.estrategiaDockVector.get(i)).nameRower;
							if(getLocalName().contains(nameRower)){
								
								Row rowOar1 = new Row();
								EstrategiaBean estrategiaBean = (EstrategiaBean)estrategia.estrategiaDockVector.get(i);
								rowOar1.setOarID(estrategiaBean.getNameOar1());//System.out.println(currentDock + " ->-->"+ nameRower);
								rowOar1.setBoat(boatTeam);							
								rowOar1.setStrength(estrategiaBean.getStrength());
								rowOar1.setDirection(estrategiaBean.getDirection());
								sendRowToWatcher(rowOar1);
								//block(500);
								//doWait(2000);
								Thread.sleep(5000L);
							}
						//}
					}
				}		
			}catch(Exception e) {
				System.out.println(Constant.NAME_ROWER + ".startRowingToWatcherBehavoiur(), error: " + e.toString());
			}
		}

		public boolean done() {
			return isRaceFinished;
		}
	}	
	
	public void sendRowToWatcher(Row row){
		try{
			/*Row row = new Row();
			String oar = Constant.NAME_OAR_1; 
			row.setOarID(oar);
			row.setBoat(boatTeam);
			row.setStrength(MyEnumStrength.STRONG.getStrength());
			row.setDirection(MyEnumDirection.FORWARD.getDirection());				
			*/
			Action actionRequestPhysicalInformation = new Action(agWatcherAid,row);
			
			ACLMessage aclMessageToWatcher = new ACLMessage(ACLMessage.REQUEST);
			aclMessageToWatcher.setLanguage(codec.getName());
			aclMessageToWatcher.setOntology(ontology.getName());
			aclMessageToWatcher.addReceiver(agWatcherAid);
			aclMessageToWatcher.setProtocol("Row");			
								
			getContentManager().fillContent(aclMessageToWatcher, actionRequestPhysicalInformation);
			
			send(aclMessageToWatcher);					
			
			//System.out.println(getLocalName() + ".sendRowToWatcher():: Row --> " + getRowInfo(row) + Constant.SD_WATCHER_X + Constant.TEAM_ID);
		}catch(Exception e) {
			System.out.println(Constant.NAME_ROWER + ".sendRowToWatcher(), error: " + e.toString());
		}
	}
	
	
	private void readPhysicalProperties(){
		ReadConfiguration.getInstance(0);			
		//
		String propTmp = ReadConfiguration.getValue("impulse_weak");
		if(propTmp != null){
			this.impulseWeak = Double.parseDouble(propTmp);					
		}
		
		propTmp = ReadConfiguration.getValue("impulse_medium");
		if(propTmp != null){
			this.impulseMedium = Double.parseDouble(propTmp);	
		}
		
		
		propTmp = ReadConfiguration.getValue("impulse_strong");
		if(propTmp != null){
			this.impulseStrong = Double.parseDouble(propTmp);	
		}
		
		propTmp = ReadConfiguration.getValue("row_seconds");
		if(propTmp != null){
			this.rowSeconds = Double.parseDouble(propTmp);	
		}
		
		//
		propTmp = ReadConfiguration.getValue("rower" + this.rowerNumber + "_strength");
		if(propTmp != null){
			this.strength = Double.parseDouble(propTmp);
		}
		
		propTmp = ReadConfiguration.getValue("rower" + this.rowerNumber + "_resistance");
		if(propTmp != null){
			this.resistance = Double.parseDouble(propTmp);
		}
		propTmp = ReadConfiguration.getValue("rower" + this.rowerNumber + "_agility");
		if(propTmp != null){
			this.agility = Double.parseDouble(propTmp);
		}
	}
	
	public long getTimeForRow(long time){
		this.timeRow = this.rowSeconds*(time-1)-this.agility*time;
		return Long.valueOf(String.valueOf(this.timeRow));
	}
	
	class ProcessSeatResponseFromBoat extends SimpleBehaviour{
		private static final long serialVersionUID = 3844912585144138107L;
		private boolean isDone = false;		
		
		public ProcessSeatResponseFromBoat(Agent agent) {
			super(agent);
		}

		public void action(){
			try{
				List<Integer> performativeList = new ArrayList<Integer>(2);
				performativeList.add(ACLMessage.INFORM);
				performativeList.add(ACLMessage.REFUSE);
				//performativeList.add(ACLMessage.NOT_UNDERSTOOD);
				List<String> protocolList = new ArrayList<String>(1);
				protocolList.add("SeatChoosed");
				MessageTemplate mt = MyAgent.addMessageTemplatOR(performativeList, protocolList);		
				ACLMessage msg =  receive(mt);	
				if(msg == null){
					block();
				}else{					
					try{						
						if(msg.getPerformative() == ACLMessage.INFORM){	
							//System.out.println(getLocalName() + ": <-- Me han aceptado el asiento " + " from: " + msg.getSender());								
						}else if(msg.getPerformative() == ACLMessage.REFUSE){		
							System.out.println(getLocalName()+ " <-- escoger otro asiento");
							//pickingSeatToBoat(false);
						}else if(msg.getPerformative() == ACLMessage.NOT_UNDERSTOOD){
							System.out.println(getLocalName()+ " <-- el watcher NOT_UNDERSTOOD el asientoSeleccionado");
						}						
					}catch(Exception e){
						System.out.println(getLocalName() + ".ProcessSeatResponseFromBoat(), error: " + e.toString());
					}
					isDone = true;
				}
			}catch(Exception e) {
				System.out.println(Constant.NAME_ROWER + ".ProcessSeatResponseFromBoat(), error: " + e.toString());
			}
		}

		public boolean done() {
			return isDone;
		}
	}

}